package com.ht.module.job.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ht.abnormal.HtException;
import com.ht.constant.Enum.JobStatusEnum;
import com.ht.module.job.entity.JobInfo;
import com.ht.module.job.mapper.JobInfoMapper;
import com.ht.module.job.service.JobInfoService;
import com.ht.util.Pager;
import jakarta.annotation.Resource;
import org.quartz.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 * 定时任务信息表，用于存储任务基本信息 服务实现类
 * </p>
 *
 * @author hejialun
 * @since 2025-08-11
 */
@Service
public class JobInfoServiceImpl extends ServiceImpl<JobInfoMapper, JobInfo> implements JobInfoService {
    @Resource
    private Scheduler scheduler;

    @Override
    public Pager<JobInfo> findPage(Pager<JobInfo> pager, JobInfo en) {
        return baseMapper.selectPage(pager,
                Wrappers.<JobInfo>lambdaQuery()
                        .eq(StrUtil.isNotEmpty(en.getJobName()),JobInfo::getJobName, en.getJobName())
                        .eq(StrUtil.isNotEmpty(en.getJobGroup()),JobInfo::getJobGroup, en.getJobGroup())
                        .eq(StrUtil.isNotEmpty(en.getStatus()),JobInfo::getStatus, en.getStatus())
                        .orderByDesc(JobInfo::getCreateDate)
        );
    }

    @Override
    @Transactional
    public void addOrUpdateJob(JobInfo en) throws SchedulerException {
        if (StrUtil.isEmpty(en.getId())) {
            baseMapper.insert(en);
        } else {
            //修改定时任务首先要停止定时任务
            JobInfo jobInfo = baseMapper.selectById(en.getId());
            if(StrUtil.equals(jobInfo.getStatus(), JobStatusEnum.RUNNING.getCode())){
                throw new HtException("定时任务正在运行中，请先停止后在修改定时任务！");
            }
            baseMapper.updateById(en);
        }
        if (StrUtil.equals(en.getStatus(), JobStatusEnum.PAUSED.getCode())) {
            //注册任务
            createOrUpdateQuartzJob(en);
            JobKey jobKey = JobKey.jobKey(en.getJobName(), en.getJobGroup());
            scheduler.pauseJob(jobKey);
        }

    }

    @Override
    @Transactional
    public void delById(String id) {
        //查询出当前定时任务
        JobInfo jobInfo = baseMapper.selectById(id);
        if (BeanUtil.isEmpty(jobInfo)) {
            throw new HtException("定时任务不存在！");
        }

        if (StrUtil.equals(jobInfo.getStatus(), JobStatusEnum.RUNNING.getCode())) {
            throw new HtException("定时任务正在运行中，不可删除！");
        }

        //删除quartz中的
        try {
            scheduler.deleteJob(JobKey.jobKey(jobInfo.getJobName(), jobInfo.getJobGroup()));
            //删除数据库的
            baseMapper.deleteById(id);
        } catch (SchedulerException e) {
            log.error("定时任务删除失败:{}", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    @Transactional
    public void pause(String id) {
        //查询出当前定时任务
        JobInfo jobInfo = baseMapper.selectById(id);
        if (BeanUtil.isEmpty(jobInfo)) {
            throw new HtException("定时任务不存在！");
        }
        try {
            scheduler.pauseJob(JobKey.jobKey(jobInfo.getJobName(), jobInfo.getJobGroup()));
            jobInfo.setStatus(JobStatusEnum.PAUSED.getCode());
            baseMapper.updateById(jobInfo);

        } catch (SchedulerException e) {
            log.error("定时任务暂停失败:{}", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    @Transactional
    public void run(String id) {
        //查询出当前定时任务
        JobInfo jobInfo = baseMapper.selectById(id);
        run(jobInfo);
    }

    @Override
    @Transactional
    public void run(JobInfo jobInfo) {
        if (BeanUtil.isEmpty(jobInfo)) {
            throw new HtException("定时任务不存在！");
        }
        try {
            //注册任务
            createOrUpdateQuartzJob(jobInfo);
            JobKey jobKey = JobKey.jobKey(jobInfo.getJobName(), jobInfo.getJobGroup());
            // 如果任务是暂停状态，则恢复
            scheduler.resumeJob(jobKey);

            jobInfo.setStatus(JobStatusEnum.RUNNING.getCode());
            baseMapper.updateById(jobInfo);

        } catch (Exception e) {
            log.error("定时任务运行失败:", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public void runOnce(String id) {
        // 查询出当前定时任务
        JobInfo jobInfo = baseMapper.selectById(id);
        if (BeanUtil.isEmpty(jobInfo)) {
            throw new HtException("定时任务不存在！");
        }
        try {
            // 动态加载任务类
            Class<?> clazz = Class.forName(jobInfo.getJobClass());
            if (!Job.class.isAssignableFrom(clazz)) {
                throw new HtException("任务类必须实现 org.quartz.Job 接口");
            }
            Class<? extends Job> jobClass = (Class<? extends Job>) clazz;

            // 唯一 ID，防止与原有任务冲突
            String onceJobName = jobInfo.getJobName() + "_once_" + System.currentTimeMillis();
            String onceJobGroup = jobInfo.getJobGroup() + "_once";

            // JobDataMap 传参
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("jobId", jobInfo.getId());
            jobDataMap.put("jobParams", jobInfo.getJobParams());

            // 构建一次性 Job
            JobDetail jobDetail = JobBuilder.newJob(jobClass)
                    .withIdentity(onceJobName, onceJobGroup)
                    .setJobData(jobDataMap)
                    .build();

            // 构建一次性 Trigger（立即执行）
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger_" + onceJobName, onceJobGroup)
                    .startNow()
                    .build();

            // 调度任务
            scheduler.scheduleJob(jobDetail, trigger);

        } catch (Exception e) {
            log.error("定时任务执行失败:{}", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 统一注册或更新 Quartz 任务的方法
     *
     * @param jobInfo
     * @throws SchedulerException
     */
    private void createOrUpdateQuartzJob(JobInfo jobInfo) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(jobInfo.getJobName(), jobInfo.getJobGroup());

        // 如果已经存在，先删除
        if (scheduler.checkExists(jobKey)) {
            scheduler.deleteJob(jobKey);
        }

        try {
            Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(jobInfo.getJobClass());
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("jobId", jobInfo.getId());
            jobDataMap.put("jobParams", jobInfo.getJobParams());

            JobDetail jobDetail = JobBuilder.newJob(jobClass)
                    .withIdentity(jobKey)
                    .setJobData(jobDataMap)
                    .build();

            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(jobInfo.getJobName() + "Trigger", jobInfo.getJobGroup())
                    .withSchedule(CronScheduleBuilder.cronSchedule(jobInfo.getCronExpression()))
                    .build();

            scheduler.scheduleJob(jobDetail, trigger);

        } catch (ClassNotFoundException e) {
            throw new RuntimeException("任务类未找到：" + jobInfo.getJobClass(), e);
        }
    }

}
